home *** CD-ROM | disk | FTP | other *** search
- Subject: v22i030: Byte Unix benchmarks, Part03/05
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 59e809aa 755afa62 4a84bcf4 0e97b252
-
- Submitted-by: "Ben Smith @ BYTE" <ben@bytepb.byte.com>
- Posting-number: Volume 22, Issue 30
- Archive-name: byte-benchmarks/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 5)."
- # Contents: bench.doc big.c dbmserv.c
- # Wrapped by rsalz@papaya.bbn.com on Tue May 8 08:55:32 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'bench.doc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'bench.doc'\"
- else
- echo shar: Extracting \"'bench.doc'\" \(14682 characters\)
- sed "s/^X//" >'bench.doc' <<'END_OF_FILE'
- X@BT
- X
- X[TITLE]BYTE's UNIX Benchmarks
- X[DEK]Separating fact from fiction in the exploding UNIX empire
- X[TOC]Before you jump into the UNIX pool, see how your favorite system stacks
- Xup against the rest of the pack.
- X
- XBen Smith
- X
- XIn making purchase decisions, it's difficult to know whom to believe. Each
- Xvendor claims, predictably, that their products are better than the
- Xcompetition's, but how does one prove, or debunk, these claims?
- X Cost and performance typically top the list of considerations for those
- Xseeking to purchase equipment, and while cost can be easily compared,
- Xperformance cannot, and comparing costs without analyzing each system's
- Xrelative value is a worthless exercise.
- X When DOS became popular, it allowed for the development of performance
- Xmeasurement programs, benchmarks, that would run on any system that ran DOS.
- XBYTE's lab technicians set about creating their own, and the BYTE DOS
- Xbenchmarks were born. Dozens of systems have been clocked using these
- Xfacilities, and each review of a new DOS-based system includes the results of
- Xthese benchmarks.
- X This is all very well, but while DOS is installed on a great many systems,
- Xit is no longer the !ITAL!only!ENDITAL! popular multi-platform operating
- Xsystem. User demands for greater expandability, better performance and
- Xmulti-tasking have turned UNIX systems into one of the fastest growing
- Xsegments of the market. When UNIX stepped from minicomputers to workstations,
- Xit established itself as the defacto OS for an exciting new breed of machine.
- XNow, with solid implementations for affordable Intel and Motorola-based
- Xplatforms, UNIX is making a name for itself in the PC realm. As UNIX finds
- Xits way into the mainstream, it is necessary to have the tools to objectively
- Xmeasure not only the performance of various hardware platforms, but of
- Xdifferent versions of UNIX as well.
- X
- X!SUBHED!Unix is Not MS-DOS!ENDSUBHED!
- XConceptually, BYTE's UNIX benchmarks are the same as BYTE's MS-DOS
- Xbenchmarks: We have combined evaluation of both low-level operations and
- Xhigh-level applications type programs to highlight the performance of the
- Xentire system.
- X But UNIX is considerably different from MS-DOS. In the first place, it is a
- X!ITAL!multi!ENDITAL!-tasking, !ITAL!multi!ENDITAL!-user operating system. It
- Xis also portable, able to run on many different kinds of computers. MS-DOS is
- Xa !ITAL!single!ENDITAL!-tasking, !ITAL!single!ENDITAL!-user operating system,
- Xand it is intended to run on essentially one kind of computer, an IBM-PC or
- XPC ``clone,'' utilizing a specific class of processor from Intel. As a
- Xresult, the UNIX benchmarks differ from their MS-DOS counterparts. Even
- Xthough there are some equivalent low-level tests, you will find that even
- Xthese run differently; the popular Dhrystone benchmark commonly gives
- Xdifferent results, on the same hardware, when run under both DOS and UNIX.
- XThe reason? Different compilers are being used, and the underlying operating
- Xsystems and services are wildly different.
- X Another important difference is that Microsoft is the only real source of
- XDOS; other suppliers simply repackage Microsoft's basic operating system
- Xunder other names. In contrast, there are many different kinds of UNIX, and
- Xwhile similarities exist (the core UNIX from Dell, Everex and Interactive
- XSystems are virtually the same), there are UNIX and UNIX-like operating
- Xsystems that differ greatly from one another. Conclusion: The UNIX benchmarks
- Xare evaluating the implementation of UNIX and the resident compiler as well
- Xas the hardware on which it is running (the MS-DOS and Apple Macintosh
- Xbenchmarks use a common compiler, the public-domain Small C).
- X With so many variables, what is constant? Well, we have established a
- Xbaseline, SCO Xenix 386 version 2.3.1. running on the Everex 386/33 with 4
- XMbytes of RAM and an 80387 math coprocessor. While it isn't UNIX per se
- X(because AT&T decides which implementations may be called ``UNIX''), it is
- Xmore popular than any other PC UNIX implementation. It is specifically
- Xdesigned for 80386-based computers with full 32 bit memory access. The Everex
- X386/33 was chosen because it is one of today's highest performance 386
- Xcomputers properly configured to run the full 32 bit operating system. (Some
- X386 computers cannot access memory through single 32 bit operations; small
- Xmatter if you are just running MS-DOS, an 8 bit operating system, but serious
- Xif you want to run UNIX.) This combination of system and OS is timely, but
- Xwe'll continue to adjust the baseline as needed to reflect the installed PC
- Xand workstation UNIX base.
- X
- X!SUBHED!The Low Level Bench Programs!ENDSUBHED!
- XThe BYTE UNIX benchmarks consist of eight groups of programs: arithmetic,
- Xsystem calls, memory operations, disk operations, dhrystone, database
- Xoperations, system loading, and miscellaneous. These can be roughly divided
- Xinto the low-level tests (arithmetic, system calls, memory, disk, and
- Xdhrystone) and high-level tests (database operations, system loading, and the
- XC-compiler test that is part of the miscellaneous set).
- X The Dhrystone test is known more formally as ``Dhrystone 2''. It performs
- Xno floating-point operations, but it does involve arrays, character strings,
- Xindirect addressing, and most of the non-floating point instructions that
- Xmight be found in an application program. It also includes conditional
- Xoperations and other common program flow controls. The output of the test is
- Xthe number of dhrystone loops per second. It is used in the BYTE benchmarks
- Xbecause of its wide selection of operations and because it is one of the most
- Xwidely run benchmark programs.
- X A future version of the BYTE UNIX benchmarks will include the Whetstone
- Xbenchmark test program, as well. The Whetstone benchmark is conceptually
- Xsimilar to the Dhrystone, but with an emphasis on math; it is a mix of
- Xfloating point and integer arithmetic, function calls, array operations,
- Xconditionals, and transcendental function calls.
- X All the arithmetic tests have the same source code with different data
- Xtypes substituted for the operations: register, short, int, long, float,
- Xdouble, and an empty loop for calculating the overhead required by the
- Xprogram. The actual test involves assignment, addition, subtraction,
- Xmultiplication, and division. Very simple. But don't bother running the float
- Xand double precision test unless you have a math co-processor; what takes a
- Xmath co-processor system 15 seconds, may take an unaided processor 30 minutes
- Xor more!
- X The system call tests are: system call overhead, pipe throughput, pipe
- Xcontext switching, spawning of child processes, execl (replacement of the
- Xcurrent process by a new process), and file read, write, and copy. The system
- Xcall overhead test evaluates the time required to do iterations of
- X!MONO!dup()!ENDMONO!, !MONO!close()!ENDMONO!, !MONO!getpid()!ENDMONO!,
- X!MONO!getuid()!ENDMONO!, and !MONO!umask()!ENDMONO! calls.
- X The pipe throughput test has no real counterpart in real-world programming;
- Xin it, a single process opens a pipe (an inter-process communications channel
- Xthat works rather like its plumbing namesake) to itself and spins a megabyte
- Xaround this short loop. You might call this the pipe overhead test. The
- Xcontext switching pipe test is more like a real-world application; the test
- Xprogram spawns a child process with which it carries on a bi-directional pipe
- Xconversation.
- X The spawn test creates a child process which immediately dies after its own
- X!MONO!fork()!ENDMONO!. The process is repeated over and over. Similarly, the
- Xexec test is a process that repeatedly changes to a new incarnation. One of
- Xthe arguments passed to the new incarnation is the number of remaining
- Xiterations (there has to be some control, after all).
- X The file read, write, and copy tests capture the number of characters that
- Xcan be written, read, and copied in a specified time (default is 10 seconds).
- XIf you run this test with the minimum element (1 second), you should see a
- Xsignificantly higher value for all operations if your system implements disk
- Xcacheing. Be sure you have plenty of disk space before you run this test.
- X
- X!SUBHED!The High-Level Bench Programs!ENDSUBHED!
- XTo qualify as a high-level test, the test must involve operations that a
- Xreal-world application program might employ, including heavy use of the CPU
- Xand disk. At the time of writing this article, we have currently implemented
- Xonly the system loading and database tests, but we will be adding several new
- Xtests in the months ahead.
- X The system loading test is a shell script that is run by 1, 2, 4, and 8
- Xconcurrent processes. The script consists of an alphabetic sort one file to
- Xanother; taking the octal dump of the result and doing a numeric sort to a
- Xthird file; running grep on the result of the alphabetic sort file;
- X!MONO!tee!ENDMONO!ing the result to a file and to !MONO!wc!ENDMONO! (word
- Xcount); writing the final result to a file; and removing all of the resulting
- Xfiles. This script was used in the original BYTE UNIX benchmarks (1983), but
- Xthe source file is several magnitudes larger than the original.
- X The C compile and link is nothing more than that.
- X The database operations consist of random read, write, and add operations
- Xon a database file. The operations are handled by a server process; the
- Xrequests come from client processes. The test is run with 1, 2, 4, and 8
- Xclient processes. The test employs semaphores and message queues. Semaphores
- Xare being used less and less these days. BSD systems use sockets instead in
- Xplace of both of these System V.3 IPC utilities. System V.4 offers both. This
- Xtest is being rewritten using sockets, but since Xenix doesn't implement
- Xsockets, our baseline configuration becomes instantly obsolete when we
- Xreplace the database test. Just another one of those little problems in
- Xtrying to create journalistic computer benchmarks: any program that has been
- Xfully debugged is probably obsolete [ Murphy, et al ].
- X
- X!SUBHED!Miscellany!ENDSUBHED!
- XThe remaining tests are in the miscellaneous group: Tower of Hanoi (a test of
- Xrecursive operations) and a test of the UNIX arbitrary precision calculator
- Xcalculating the square root of two to 99 decimal places.
- X No doubt, we will be adding tests to this suite as we see the need to test
- Xand evaluate from different perspectives.
- X
- X!SUBHED!Problems in the Modern World!ENDSUBHED!
- XThe major problem we have had with developing the UNIX benchmark programs is
- Xdesigning them so that they fairly reflect the strengths and weaknesses of
- Xall the systems on which we anticipate using them. For example, the
- Xoperations should allow RISC machines to give appropriately high performance
- Xfor the sorts of operations that RISC is good for, and should also illustrate
- Ximprovements provided by faster bus speeds, better math coprocessors and the
- Xlike. In the case of RISC, the efficiency of the compiler is of utmost
- Ximportance; RISC compilers must rearrange instructions to take advantage of
- Xinstruction pipelining (for an overview of RISC, see BYTE, May 1988).
- X The majority of the UNIX systems that we look at employ disk caching. This
- Xis especially important because modern UNIX includes swapping and paging out
- Xto disk when there is insufficient memory for a task or the number of tasks.
- XIt is an interesting exercise to run the disk file operations test with
- Xincreasingly large files and note the point at which performance drops.
- X
- X!SUBHED!How They Work!ENDSUBHED!
- XA 400 line Bourne shell script (!MONO!Run!ENDMONO!) administers the
- Xbenchmarking system. After the evaluation of the command line options, the
- Xbenchmarking operation for each test has three stages: parameter setup,
- Xtiming the execution of the test, and calculation/formatting operations (see
- XFigure 1). After !MONO!Run!ENDMONO! determines the parameters for the test,
- Xit sends a formatted description to the output file. !MONO!Run!ENDMONO! then
- Xinvokes the specific test by means of the UNIX command !MONO!time!ENDMONO!.
- XThe output of !MONO!time!ENDMONO! and any output from the test itself end up
- Xin a raw data file. Most tests are run six times so that any variance can be
- Xaveraged. On completion of a set of tests, !MONO!Run!ENDMONO! invokes a
- Xcleanup script, which does the statistical calculations on the raw data using
- Xthe !MONO!awk!ENDMONO! formatting language.
- X The greater part of the benchmark programs are written in C and are
- Xcompiled on the test machine prior to running the tests.
- X
- X!SUBHED!Using the Results!ENDSUBHED!
- XIf all you need is a raw measure of performance, then feel free to use the
- XDhrystone and Whetstone tests as indices of just that. But if you want to use
- Xthe benchmarks to evaluate a machine's ability to serve some real need, then
- Xyou should do the following:
- X1. Analyze your requirements as far as the type of computing, amount and type
- Xof communications I/O, and amount and type of disk I/O.
- X2. Score the subject machines using weighting factors that reflect your
- Xrequirements.
- X3. Generate a price vs. performance plot.
- X4. Use the price vs. performance, along with information about the
- Xreliability servicability of the hardware.
- X Step 4 is really more of an art than anything else. It is extremely
- Ximportant, however, to not rely on price vs. performance alone.
- X We use our UNIX Benchmarks for doing a rough analysis and comparison of
- Xdivergent machines. (See figure 2, ``UNIX Machines Tested.'') As you can see,
- Xwe even go so far as to generate a single index number, a sort of reduction
- Xof all of the benchmark tests to a single value. This index is generated by
- Xsumming the the individual indices of the dhrystone test, the floating point
- Xtest, the shell test with eight concurrent processes, the C compiler time,
- Xthe !MONO!dc!ENDMONO! routine, and the tower of hanoi time. By definition,
- Xthe combined index for the baseline machine is six. Indicess above six imply
- Xa better overall performance than the baseline machine; indices less than
- Xsix, worse performance. Always keep in mind that having a single index rating
- Xfor a machine may make good cocktail conversation, but it is incredibly
- Xsimplistic. It is like reducing a complex sculptural shape to a single point;
- Xyou no longer can tell what you are looking at. This number doesn't reflect
- Xany real-world use of a UNIX system. However, the index is devised so that it
- Xgives an overall indication of different kinds of system operations and so is
- Xvaluable to our reviews.
- X BYTE's UNIX benchmarking suite is small enough to port easily to any UNIX
- Xsystem, yet diverse and flexible enough to be useful for a wide spectrum of
- Xbenchmarking requirements. Besides, they're in the public domain, so they can
- Xbe obtained for little, if any, cost. What better reason do you need to use
- Xthem?
- END_OF_FILE
- if test 14682 -ne `wc -c <'bench.doc'`; then
- echo shar: \"'bench.doc'\" unpacked with wrong size!
- fi
- chmod +x 'bench.doc'
- # end of 'bench.doc'
- fi
- if test -f 'big.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'big.c'\"
- else
- echo shar: Extracting \"'big.c'\" \(13750 characters\)
- sed "s/^X//" >'big.c' <<'END_OF_FILE'
- X/*******************************************************************************
- X * The BYTE UNIX Benchmarks - Release 2
- X * Module: big.c SID: 2.4 4/17/90 16:45:31
- X *
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Ben Smith or Rick Grehan at BYTE Magazine
- X * bensmith@bixpb.UUCP rick_g@bixpb.UUCP
- X *
- X *******************************************************************************
- X * Modification Log:
- X *
- X ******************************************************************************/
- Xchar SCCSid[] = "@(#) @(#)big.c:2.4 -- 4/17/90 16:45:31";
- X/*
- X * dummy code for execl test [ old version of makework.c ]
- X *
- X * makework [ -r rate ] [ -c copyfile ] nusers
- X *
- X * job streams are specified on standard input with lines of the form
- X * full_path_name_for_command [ options ] [ <standard_input_file ]
- X *
- X * "standard input" is send to all nuser instances of the commands in the
- X * job streams at a rate not in excess of "rate" characters per second
- X * per command
- X *
- X */
- X
- X#include <stdio.h>
- X#include <signal.h>
- X
- X#define DEF_RATE 5.0
- X#define GRANULE 5
- X#define CHUNK 60
- X#define MAXCHILD 12
- X#define MAXWORK 10
- X
- Xfloat thres;
- Xfloat est_rate = DEF_RATE;
- Xint nusers; /* number of concurrent users to be simulated by
- X * this process */
- Xint firstuser; /* ordinal identification of first user for this
- X * process */
- Xint nwork = 0; /* number of job streams */
- Xint exit_status = 0; /* returned to parent */
- Xint sigpipe; /* pipe write error flag */
- X
- Xstruct st_work {
- X char *cmd; /* name of command to run */
- X char **av; /* arguments to command */
- X char *input; /* standard input buffer */
- X int inpsize; /* size of standard input buffer */
- X char *outf; /* standard output (filename) */
- X} work[MAXWORK];
- X
- Xstruct {
- X int xmit; /* # characters sent */
- X char *bp; /* std input buffer pointer */
- X int blen; /* std input buffer length */
- X int fd; /* stdin to command */
- X int pid; /* child PID */
- X char *line; /* start of input line */
- X int firstjob; /* inital piece of work */
- X int thisjob; /* current piece of work */
- X} child[MAXCHILD], *cp;
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X int i;
- X int l;
- X int fcopy = 0; /* fd for copy output */
- X int master = 1; /* the REAL master, == 0 for clones */
- X int nchild; /* no. of children for a clone to run */
- X int done; /* count of children finished */
- X int output; /* aggregate output char count for all
- X children */
- X int c;
- X int thiswork = 0; /* next job stream to allocate */
- X int nch; /* # characters to write */
- X int written; /* # characters actully written */
- X char logname[15]; /* name of the log file(s) */
- X int onalarm();
- X int pipeerr();
- X int wrapup();
- X int grunt();
- X int pvec[2]; /* for pipes */
- X char *p;
- X char *prog; /* my name */
- X
- X#if ! debug
- X freopen("masterlog.00", "a", stderr);
- X#endif
- X fprintf(stderr, "*** New Run *** ");
- X prog = argv[0];
- X while (argc > 1 && argv[1][0] == '-') {
- X p = &argv[1][1];
- X argc--;
- X argv++;
- X while (*p) {
- X switch (*p) {
- X case 'r':
- X est_rate = atoi(argv[1]);
- X sscanf(argv[1], "%f", &est_rate);
- X if (est_rate <= 0) {
- X fprintf(stderr, "%s: bad rate, reset to %.2f chars/sec\n", prog, DEF_RATE);
- X est_rate = DEF_RATE;
- X }
- X argc--;
- X argv++;
- X break;
- X
- X case 'c':
- X fcopy = open(argv[1], 1);
- X if (fcopy < 0)
- X fcopy = creat(argv[1], 0600);
- X if (fcopy < 0) {
- X fprintf(stderr, "%s: cannot open copy file '%s'\n",
- X prog, argv[1]);
- X exit(2);
- X }
- X lseek(fcopy, 0L, 2); /* append at end of file */
- X argc--;
- X argv++;
- X break;
- X
- X default:
- X fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
- X exit(4);
- X }
- X p++;
- X }
- X }
- X
- X if (argc < 2) {
- X fprintf(stderr, "%s: missing nusers\n", prog);
- X exit(4);
- X }
- X
- X nusers = atoi(argv[1]);
- X if (nusers < 1) {
- X fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
- X exit(4);
- X }
- X fprintf(stderr, "%d Users\n", nusers);
- X argc--;
- X argv++;
- X
- X /* build job streams */
- X getwork();
- X#if debug
- X dumpwork();
- X#endif
- X
- X /* clone copies of myself to run up to MAXCHILD jobs each */
- X firstuser = MAXCHILD;
- X fprintf(stderr, "master pid %d\n", getpid());
- X fflush(stderr);
- X while (nusers > MAXCHILD) {
- X fflush(stderr);
- X if (nusers >= 2*MAXCHILD)
- X /* the next clone must run MAXCHILD jobs */
- X nchild = MAXCHILD;
- X else
- X /* the next clone must run the leftover jobs */
- X nchild = nusers - MAXCHILD;
- X if ((l = fork()) == -1) {
- X /* fork failed */
- X fatal("** clone fork failed **\n");
- X goto bepatient;
- X } else if (l > 0) {
- X fprintf(stderr, "master clone pid %d\n", l);
- X /* I am the master with nchild fewer jobs to run */
- X nusers -= nchild;
- X firstuser += MAXCHILD;
- X continue;
- X } else {
- X /* I am a clone, run MAXCHILD jobs */
- X#if ! debug
- X sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
- X freopen(logname, "w", stderr);
- X#endif
- X master = 0;
- X nusers = nchild;
- X break;
- X }
- X }
- X if (master)
- X firstuser = 0;
- X
- X close(0);
- X for (i = 0; i < nusers; i++ ) {
- X fprintf(stderr, "user %d job %d ", firstuser+i, thiswork);
- X if (pipe(pvec) == -1) {
- X /* this is fatal */
- X fatal("** pipe failed **\n");
- X goto bepatient;
- X }
- X fflush(stderr);
- X if ((child[i].pid = fork()) == 0) {
- X int fd;
- X /* the command */
- X if (pvec[0] != 0) {
- X close(0);
- X dup(pvec[0]);
- X }
- X#if ! debug
- X sprintf(logname, "userlog.%02d", firstuser+i);
- X freopen(logname, "w", stderr);
- X#endif
- X for (fd = 3; fd < 24; fd++)
- X close(fd);
- X if (work[thiswork].outf[0] != '\0') {
- X /* redirect std output */
- X char *q;
- X for (q = work[thiswork].outf; *q != '\n'; q++) ;
- X *q = '\0';
- X if (freopen(work[thiswork].outf, "w", stdout) == NULL) {
- X fprintf(stderr, "makework: cannot open %s for std output\n",
- X work[thiswork].outf);
- X fflush(stderr);
- X }
- X *q = '\n';
- X }
- X execv(work[thiswork].cmd, work[thiswork].av);
- X /* don't expect to get here! */
- X fatal("** exec failed **\n");
- X goto bepatient;
- X }
- X else if (child[i].pid == -1) {
- X fatal("** fork failed **\n");
- X goto bepatient;
- X }
- X else {
- X close(pvec[0]);
- X child[i].fd = pvec[1];
- X child[i].line = child[i].bp = work[thiswork].input;
- X child[i].blen = work[thiswork].inpsize;
- X child[i].thisjob = thiswork;
- X child[i].firstjob = thiswork;
- X fprintf(stderr, "pid %d pipe fd %d", child[i].pid, child[i].fd);
- X if (work[thiswork].outf[0] != '\0') {
- X char *q;
- X fprintf(stderr, " > ");
- X for (q=work[thiswork].outf; *q != '\n'; q++)
- X fputc(*q, stderr);
- X }
- X fputc('\n', stderr);
- X thiswork++;
- X if (thiswork >= nwork)
- X thiswork = 0;
- X }
- X }
- X fflush(stderr);
- X
- X srand(time(0));
- X thres = 0;
- X done = output = 0;
- X for (i = 0; i < nusers; i++) {
- X if (child[i].blen == 0)
- X done++;
- X else
- X thres += est_rate * GRANULE;
- X }
- X est_rate = thres;
- X
- X signal(SIGALRM, onalarm);
- X signal(SIGPIPE, pipeerr);
- X alarm(GRANULE);
- X while (done < nusers) {
- X for (i = 0; i < nusers; i++) {
- X cp = &child[i];
- X if (cp->xmit >= cp->blen) continue;
- X l = rand() % CHUNK + 1; /* 1-CHUNK chars */
- X if (l == 0) continue;
- X if (cp->xmit + l > cp->blen)
- X l = cp->blen - cp->xmit;
- X p = cp->bp;
- X cp->bp += l;
- X cp->xmit += l;
- X#if debug
- X fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
- X#endif
- X while (p < cp->bp) {
- X if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
- X /* write it out */
- X nch = p - cp->line + 1;
- X if ((written = write(cp->fd, cp->line, nch)) != nch) {
- X /* argh! */
- X cp->line[nch] = '\0';
- X fprintf(stderr, "user %d job %d cmd %s ",
- X firstuser+i, cp->thisjob, cp->line);
- X fprintf(stderr, "write(,,%d) returns %d\n", nch, written);
- X if (sigpipe)
- X fatal("** SIGPIPE error **\n");
- X else
- X fatal("** write error **\n");
- X goto bepatient;
- X
- X }
- X if (fcopy)
- X write(fcopy, cp->line, p - cp->line + 1);
- X#if debug
- X fprintf(stderr, "child %d gets \"", i);
- X {
- X char *q = cp->line;
- X while (q <= p) {
- X if (*q >= ' ' && *q <= '~')
- X fputc(*q, stderr);
- X else
- X fprintf(stderr, "\\%03o", *q);
- X q++;
- X }
- X }
- X fputc('"', stderr);
- X#endif
- X cp->line = &p[1];
- X }
- X p++;
- X }
- X if (cp->xmit >= cp->blen) {
- X done++;
- X close(cp->fd);
- X#if debug
- X fprintf(stderr, "child %d, close std input\n", i);
- X#endif
- X }
- X output += l;
- X }
- X while (output > thres) {
- X pause();
- X#if debug
- X fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
- X#endif
- X }
- X }
- X
- Xbepatient:
- X alarm(0);
- X/****
- X * If everything is going OK, we should simply be able to keep
- X * looping unitil 'wait' fails, however some descendent process may
- X * be in a state from which it can never exit, and so a timeout
- X * is used.
- X * 5 minutes should be ample, since the time to run all jobs is of
- X * the order of 5-10 minutes, however some machines are painfully slow,
- X * so the timeout has been set at 20 minutes (1200 seconds).
- X ****/
- X signal(SIGALRM, grunt);
- X alarm(1200);
- X while ((c = wait(&l)) != -1) {
- X for (i = 0; i < nusers; i++) {
- X if (c == child[i].pid) {
- X fprintf(stderr, "user %d job %d pid %d done", firstuser+i, child[i].thisjob, c);
- X if (l != 0) {
- X if (l & 0x7f)
- X fprintf(stderr, " status %d", l & 0x7f);
- X if (l & 0xff00)
- X fprintf(stderr, " exit code %d", (l>>8) & 0xff);
- X exit_status = 4;
- X }
- X fputc('\n', stderr);
- X c = child[i].pid = -1;
- X break;
- X }
- X }
- X if (c != -1) {
- X fprintf(stderr, "master clone done, pid %d ", c);
- X if (l != 0) {
- X if (l & 0x7f)
- X fprintf(stderr, " status %d", l & 0x7f);
- X if (l & 0xff00)
- X fprintf(stderr, " exit code %d", (l>>8) & 0xff);
- X exit_status = 4;
- X }
- X fputc('\n', stderr);
- X }
- X }
- X alarm(0);
- X wrapup("Finished waiting ...");
- X
- X
- X}
- X
- Xonalarm()
- X{
- X thres += est_rate;
- X signal(SIGALRM, onalarm);
- X alarm(GRANULE);
- X}
- X
- Xgrunt()
- X{
- X /* timeout after label "bepatient" in main */
- X exit_status = 4;
- X wrapup("Timed out waiting for jobs to finish ...");
- X}
- X
- Xpipeerr()
- X{
- X sigpipe++;
- X}
- X
- Xwrapup(reason)
- Xchar *reason;
- X{
- X int i;
- X int killed = 0;
- X fflush(stderr);
- X for (i = 0; i < nusers; i++) {
- X if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
- X if (!killed) {
- X killed++;
- X fprintf(stderr, "%s\n", reason);
- X fflush(stderr);
- X }
- X fprintf(stderr, "user %d job %d pid %d killed off\n", firstuser+i, child[i].thisjob, child[i].pid);
- X fflush(stderr);
- X }
- X }
- X exit(exit_status);
- X}
- X
- Xgetwork()
- X{
- X int i;
- X int f;
- X int ac;
- X char *lp;
- X char *q;
- X struct st_work *w;
- X char line[512];
- X char c;
- X char *malloc(), *realloc();
- X
- X while (gets(line) != NULL) {
- X if (nwork >= MAXWORK) {
- X fprintf(stderr, stderr, "Too many jobs specified, .. increase MAXWORK\n");
- X exit(4);
- X }
- X w = &work[nwork];
- X lp = line;
- X i = 1;
- X while (*lp && *lp != ' ') {
- X i++;
- X lp++;
- X }
- X w->cmd = (char *)malloc(i);
- X strncpy(w->cmd, line, i-1);
- X w->cmd[i-1] = '\0';
- X w->inpsize = 0;
- X w->input = "";
- X /* start to build arg list */
- X ac = 2;
- X w->av = (char **)malloc(2*sizeof(char *));
- X q = w->cmd;
- X while (*q) q++;
- X q--;
- X while (q >= w->cmd) {
- X if (*q == '/') {
- X q++;
- X break;
- X }
- X q--;
- X }
- X w->av[0] = q;
- X while (*lp) {
- X if (*lp == ' ') {
- X /* space */
- X lp++;
- X continue;
- X }
- X else if (*lp == '<') {
- X /* standard input for this job */
- X q = ++lp;
- X while (*lp && *lp != ' ') lp++;
- X c = *lp;
- X *lp = '\0';
- X if ((f = open(q, 0)) == -1) {
- X fprintf(stderr, "cannot open input file (%s) for job %d\n",
- X q, nwork);
- X exit(4);
- X }
- X /* gobble input */
- X w->input = (char *)malloc(512);
- X while ((i = read(f, &w->input[w->inpsize], 512)) > 0) {
- X w->inpsize += i;
- X w->input = (char *)realloc(w->input, w->inpsize+512);
- X }
- X w->input = (char *)realloc(w->input, w->inpsize);
- X close(f);
- X /* extract stdout file name from line beginning "C=" */
- X w->outf = "";
- X for (q = w->input; q < &w->input[w->inpsize-10]; q++) {
- X if (*q == '\n' && strncmp(&q[1], "C=", 2) == 0) {
- X w->outf = &q[3];
- X break;
- X }
- X }
- X#if debug
- X if (*w->outf) {
- X fprintf(stderr, "stdout->");
- X for (q=w->outf; *q != '\n'; q++)
- X fputc(*q, stderr);
- X fputc('\n', stderr);
- X }
- X#endif
- X }
- X else {
- X /* a command option */
- X ac++;
- X w->av = (char **)realloc(w->av, ac*sizeof(char *));
- X q = lp;
- X i = 1;
- X while (*lp && *lp != ' ') {
- X lp++;
- X i++;
- X }
- X w->av[ac-2] = (char *)malloc(i);
- X strncpy(w->av[ac-2], q, i-1);
- X w->av[ac-2][i-1] = '\0';
- X }
- X }
- X w->av[ac-1] = (char *)0;
- X nwork++;
- X }
- X}
- X
- X#if debug
- Xdumpwork()
- X{
- X int i;
- X int j;
- X
- X for (i = 0; i < nwork; i++) {
- X fprintf(stderr, "job %d: cmd: %s\n", i, work[i].cmd);
- X j = 0;
- X while (work[i].av[j]) {
- X fprintf(stderr, "argv[%d]: %s\n", j, work[i].av[j]);
- X j++;
- X }
- X fprintf(stderr, "input: %d chars text: ", work[i].inpsize);
- X if (work[i].input == (char *)0)
- X fprintf(stderr, "<NULL>\n");
- X else {
- X register char *pend;
- X char *p;
- X char c;
- X p = work[i].input;
- X while (*p) {
- X pend = p;
- X while (*pend && *pend != '\n')
- X pend++;
- X c = *pend;
- X *pend = '\0';
- X fprintf(stderr, "%s\n", p);
- X *pend = c;
- X p = &pend[1];
- X }
- X }
- X }
- X}
- X#endif
- X
- Xfatal(s)
- Xchar *s;
- X{
- X int i;
- X fprintf(stderr, s);
- X fflush(stderr);
- X perror("Reason?");
- X fflush(stderr);
- X for (i = 0; i < nusers; i++) {
- X if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
- X fprintf(stderr, "pid %d killed off\n", child[i].pid);
- X fflush(stderr);
- X }
- X }
- X exit_status = 4;
- X return;
- X}
- END_OF_FILE
- if test 13750 -ne `wc -c <'big.c'`; then
- echo shar: \"'big.c'\" unpacked with wrong size!
- fi
- chmod +x 'big.c'
- # end of 'big.c'
- fi
- if test -f 'dbmserv.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dbmserv.c'\"
- else
- echo shar: Extracting \"'dbmserv.c'\" \(15460 characters\)
- sed "s/^X//" >'dbmserv.c' <<'END_OF_FILE'
- X/*******************************************************************************
- X * The BYTE UNIX Benchmarks - Release 2
- X * Module: dbmserv.c SID: 2.4 4/17/90 16:45:37
- X *
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Ben Smith or Rick Grehan at BYTE Magazine
- X * bensmith@bixpb.UUCP rick_g@bixpb.UUCP
- X *
- X *******************************************************************************
- X * Modification Log:
- X * change output to stdout 4/13/89 ben
- X * errors to stderr 5/24/89 ben
- X * added activity counters and ifdef time output
- X * 7/6/89 - Removed global semaphore use. Callers pid now goes
- X * into type field of message. Semaphore now only controls
- X * append operation and indicates presence of server. RG
- X * 7/11/89 - Semaphores are back. One controls extending the file,
- X * the other controls the number of people simultaneously allowed
- X * on the request queue. This latter semaphore must be tuned for
- X * a particular system to keep it from deadlocking.
- X******************************************************************************/
- X/*
- X * Multi-user DBMS simulation.
- X * Server
- X * Database has the form:
- X * IIIINNNNNNNNNNNNNNNNNNNNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPPPPPPPPPP
- X * Where IIII is the 4-digit id number (0-padded)
- X * NN... is the 20-character name
- X * AA... is the 40-character address
- X * PP... is the 10-character phone number
- X * Records are accessed by ID number (1 is the 0th record, 2 is 1st..etc.)
- X */
- Xchar id[] = "@(#) @(#)dbmserv.c:1.5 -- 7/10/89 18:54:58";
- X
- X#include <stdio.h>
- X#include <setjmp.h>
- X#include <ctype.h>
- X#include <errno.h>
- X#include <sys/types.h>
- X#include <sys/signal.h>
- X#include <sys/ipc.h>
- X#include <sys/msg.h>
- X#include <sys/param.h>
- X#include <sys/sem.h>
- X
- X#ifdef VERBOSE
- X#define DEBUG /* remove after debugging */
- X#endif
- X
- X#define ERROR (-1)
- X#define QERR 1
- X
- X#define SEEK_SET 0
- X#define SEEK_END 2
- X
- X#define RMODE 0644
- X#define WMODE 0666
- X
- X/*
- X** Record definitions.
- X*/
- X
- X#define IDLEN 4
- X#define NAMELEN 20
- X#define ADDRLEN 40
- X#define PHONLEN 10
- X#define RECLEN 74 /* Sum of the above. */
- X
- X/*
- X** Queue and semaphore names. Queues are neamed from client's
- X** point of view
- X*/
- X#define RQUEUE "WRIT" /* Read queue */
- X#define WQUEUE "READ" /* Write queue */
- X#define SEMA "SEMA" /* Semaphore */
- X/*
- X** Message types.
- X*/
- X#define READREQ 1 /* Read a record */
- X#define WRITEREQ 2 /* Write a record */
- X#define ADDREQ 3 /* Add a new record */
- X#define GETLREQ 4 /* Get largest record number */
- X#define RESULTREQ 10 /* Record contains results figures */
- X /* Results are stored as:
- X * nnnnnnnnnnmmmmmmmmmm
- X * n = total time
- X * m = number of errors
- X */
- X#define DIEREQ 99 /* Orders server to terminate. */
- X
- X/*
- X** Return codes.
- X*/
- X#define AOK 1 /* Request met ok */
- X#define DERR_RNF 2 /* Record not found */
- X#define DERR_RAE 3 /* Record already exists */
- X#define DERR_WRD 4 /* Unexplainable error */
- X#define DERR_UNK 9 /* Unknown request type */
- X/*
- X** Structures.
- X*/
- X
- Xtypedef struct {
- X int request; /* Request type and response code */
- X char recdat[RECLEN]; /* DBMS record data */
- X} msgdata;
- X
- Xtypedef struct {
- X long type; /* Holds caller's pid */
- X msgdata data; /* Pointer to request and data */
- X} amess;
- X
- X
- Xstruct ticker { unsigned long real,
- X system,
- X cpu; };
- X/*
- X** Structure instances.
- X*/
- Xamess hisreq;
- Xamess myresp;
- X
- X/* Semaphore operations for initially unlocking the queue and
- X** append semaphores. */
- X
- Xstruct sembuf unlock0;
- Xstruct sembuf unlock1 = {1 , 1, SEM_UNDO};
- X
- XFILE *dbfp; /* Pointer for database file */
- Xint readq; /* ID of read queue */
- Xint writeq; /* ID of write queue */
- Xint qsize; /* Size of read/write queues */
- Xint qsema; /* ID of queue semaphore */
- Xjmp_buf myjump; /* Jump buffer for signals */
- X#ifdef VERBOSE
- Xstruct ticker total_time = {0L, 0L, 0L}; /* Total time */
- X#endif
- Xunsigned long rd_cnt, /* read request counter */
- X wr_cnt, /* write request counter */
- X ad_cnt, /* add request counter */
- X gt_cnt, /* get request counter */
- X rs_cnt; /* result request counter */
- Xunsigned long errcnt; /* Total error count */
- Xunsigned long total_tasks; /* Total number of tasks logged in */
- X
- Xextern int errno;
- X
- X/*
- X** Function defs.
- X*/
- Xint capt_sig();
- Xkey_t makey();
- X
- X
- X/******************************************************************
- X # # ## # # #
- X ## ## # # # ## #
- X # ## # # # # # # #
- X # # ###### # # # #
- X # # # # # # ##
- X # # # # # # #
- X********************************************************************/
- X
- Xmain(argc,argv,envp)
- Xint argc;
- Xchar *argv[];
- Xchar **envp;
- X
- X{
- X
- X /*
- X ** User must specify database name and queue size.
- X */
- X if(argc<3)
- X {
- X fprintf(stderr,"usage: %s dbasefile queuesize\n",argv[0]);
- X exit(1);
- X }
- X
- X /*
- X ** The file must already exist.
- X */
- X if((dbfp=fopen(argv[1],"r+"))==(FILE *)NULL)
- X {
- X fprintf(stderr,"**Open error on: %s\n",argv[1]);
- X exit(1);
- X }
- X
- X /*
- X ** Get queuesize value.
- X */
- X if((qsize=atoi(argv[2]))<=0)
- X {
- X fprintf(stderr,"**Illegal queue size\n");
- X exit(1);
- X }
- X unlock0.sem_num = 0; /* Build unlock structure */
- X unlock0.sem_op = (short)qsize;
- X unlock0.sem_flg = (short)SEM_UNDO;
- X
- X /*
- X ** Set up the message queues.
- X */
- X if((readq=msgget(makey(RQUEUE),IPC_CREAT|IPC_EXCL|RMODE))==
- X ERROR)
- X {
- X qerror("**Cannot create read queue");
- X cleanup();
- X exit(1);
- X }
- X
- X if((writeq=msgget(makey(WQUEUE),IPC_CREAT|IPC_EXCL|WMODE))==
- X ERROR)
- X {
- X qerror("**Cannot create write queue");
- X cleanup();
- X exit(1);
- X }
- X
- X /*
- X ** Initialize stuff.
- X */
- X errcnt=0L;
- X total_tasks=0L;
- X rd_cnt=0L;
- X wr_cnt=0L;
- X ad_cnt=0L;
- X gt_cnt=0L;
- X rs_cnt=0L;
- X
- X /*
- X ** Set up the semaphores and unlock them (2 semaphores in the set).
- X */
- X if((qsema=semget(makey(SEMA),2,IPC_CREAT|IPC_EXCL|WMODE))==
- X ERROR)
- X {
- X serror("**Cannot create semaphore");
- X cleanup();
- X exit(1);
- X }
- X if((semop(qsema,&unlock1,1)==ERROR) ||
- X (semop(qsema,&unlock0,1)==ERROR))
- X {
- X serror("Unlocking semaphore");
- X cleanup();
- X exit(1);
- X }
- X
- X /*
- X ** Service requests from the outside world.
- X */
- X if(servicer())
- X {
- X fprintf(stderr,"**Server error**\n");
- X fprintf(stderr,"**Errcode: %d\n",errno);
- X fprintf(stderr,"**REQ: %ld\n",hisreq.type);
- X }
- X
- X /*
- X ** Output results.
- X */
- X {
- X#ifdef VERBOSE
- X fprintf(stdout,"Time: cpu %ld system %ld real %ld\n",
- X total_time.cpu, total_time.system, total_time.real);
- X fprintf(stdout,"Error : %ld Tasks logged: %ld\n",
- X errcnt, total_tasks);
- X fprintf(stdout,
- X" %ld read; %ld write; %ld add; %ld get-last; %ld result: %ld errors\n",
- X rd_cnt, wr_cnt, ad_cnt, gt_cnt, rs_cnt, errcnt);
- X#endif
- X }
- X
- X /*
- X ** Close everything down.
- X */
- X cleanup();
- X exit(0); /* Good night, ladies. */
- X}
- X
- X/**************************** servicer *********************
- X** servicer()
- X** This routine handles all the requests coming in on the
- X** read message queue. Responses are sent along the write
- X** message queque.
- X*************************************************************/
- Xservicer()
- X{
- X#ifdef VERBOSE
- X unsigned long cpu_time,system_time,real_time;
- X#endif
- X unsigned long aderr;
- X char idnum[IDLEN+1];
- X char buff[RECLEN+1];
- X int rcod;
- X
- X /*
- X ** First set all the signals to capture.
- X */
- X setsignals();
- X
- X /*
- X ** Build a longjump.
- X */
- X if(setjmp(myjump)!=0)
- X return(0);
- X
- X /*
- X ** Now loop and process messages.
- X */
- X while(1)
- X {
- X if(msgrcv(readq,&hisreq,RECLEN,0,MSG_NOERROR)<0)
- X return(QERR); /* Error return */
- X#ifdef DEBUG
- Xprintf("receiving %d requwest\n",hisreq.data.request);
- X#endif
- X
- X
- X switch(hisreq.data.request)
- X {
- X
- X /*
- X ** Read operation.
- X */
- X case READREQ:
- X ++rd_cnt;
- X strncpy(idnum,hisreq.data.recdat,4);
- X rcod=doread(idnum,buff);
- X if(rcod==AOK)
- X strncpy(myresp.data.recdat,buff,RECLEN);
- X myresp.data.request=rcod;
- X myresp.type=hisreq.type;
- X if(msgsnd(writeq,&myresp,RECLEN,0)<0)
- X return(QERR);
- X#ifdef DEBUG
- Xprintf("returning response\n");
- X#endif
- X
- X break;
- X
- X /*
- X ** Write operation.
- X */
- X case WRITEREQ:
- X ++wr_cnt;
- X myresp.data.request=(long)dowrite(hisreq.data.recdat);
- X myresp.type=hisreq.type;
- X if(msgsnd(writeq,&myresp,RECLEN,0)<0)
- X return(QERR);
- X break;
- X
- X /*
- X ** Add operation.
- X */
- X case ADDREQ:
- X ++ad_cnt;
- X myresp.data.request=(long)doadd(hisreq.data.recdat);
- X myresp.type=hisreq.type;
- X if(msgsnd(writeq,&myresp,RECLEN,0)<0)
- X return(QERR);
- X break;
- X
- X /*
- X ** Get-last-record-in-file operation.
- X */
- X case GETLREQ:
- X ++gt_cnt;
- X myresp.data.request=(long)dotell(myresp.data.recdat);
- X myresp.type=hisreq.type;
- X if(msgsnd(writeq,&myresp,RECLEN,0)<0)
- X return(QERR);
- X break;
- X
- X /*
- X ** Record task's results operation.
- X ** Note that this operation requires no
- X ** response.
- X */
- X case RESULTREQ:
- X ++rs_cnt;
- X#ifdef VERBOSE
- X sscanf(hisreq.data.recdat,"%ld %ld %ld %d",
- X &cpu_time,&system_time,&real_time,&aderr);
- X total_time.cpu+=cpu_time;
- X total_time.system+=system_time;
- X total_time.real+=real_time;
- X#else
- X sscanf(hisreq.data.recdat,"%d", &aderr);
- X#endif
- X errcnt+=aderr;
- X total_tasks++;
- X break;
- X
- X /*
- X ** We have been asked to leave.
- X */
- X case DIEREQ:
- X return(0);
- X
- X /*
- X ** Eh?
- X */
- X default:
- X myresp.data.request=DERR_UNK;
- X myresp.type=hisreq.type;
- X if(msgsnd(writeq,&myresp,RECLEN,0)<0)
- X return(QERR);
- X break;
- X }
- X }
- X}
- X
- X/**************************** doread *********************
- X** Perform a read request.
- X*************************************************************/
- Xdoread(idnum,buff)
- Xchar idnum[IDLEN+1];
- Xchar buff[RECLEN];
- X{
- X long offset;
- X
- X /*
- X ** Calculate offset.
- X */
- X idnum[IDLEN]='\0';
- X offset=(atol(idnum)-1)*(long)RECLEN;
- X if(offset<0L) return(DERR_RNF); /* Illegal offset */
- X
- X if( (fseek(dbfp,offset,SEEK_SET)!=0) ||
- X (fread(buff,RECLEN,1,dbfp)!=1) )
- X return(DERR_RNF); /* Seek or read failed */
- X
- X return(AOK); /* No problems */
- X}
- X
- X/**************************** dowrite *********************
- X** Perform a write request.
- X*************************************************************/
- Xdowrite(buff)
- Xchar buff[RECLEN];
- X{
- X char idnum[IDLEN+1];
- X long offset;
- X
- X strncpy(idnum,buff,4); /* Get id number */
- X
- X /*
- X ** Calculate offset.
- X */
- X idnum[IDLEN]='\0';
- X offset=(atol(idnum)-1)*(long)RECLEN;
- X if(offset<0L) return(DERR_RNF); /* Illegal offset */
- X
- X if((fseek(dbfp,offset,SEEK_SET)!=0) ||
- X (fwrite(buff,RECLEN,1,dbfp)!=1))
- X return(DERR_RNF);
- X
- X return(AOK);
- X}
- X
- X/**************************** doadd *********************
- X** Perform an add request.
- X*************************************************************/
- Xdoadd(buff)
- Xchar buff[RECLEN];
- X{
- X
- X long offset;
- X
- X /* Seek to the end of the file. */
- X if(fseek(dbfp,0L,SEEK_END)!=0)
- X return(DERR_WRD); /* Huh? */
- X
- X /* Get offset -- we presume caller has proper id set */
- X offset=ftell(dbfp);
- X if (fwrite(buff,RECLEN,1,dbfp)!=1)
- X return(DERR_RNF); /* Failed write */
- X
- X return(AOK);
- X}
- X
- X/**************************** dotell *********************
- X** Perform a "tell" request.
- X** Returns highest current id number in file.
- X*************************************************************/
- Xdotell(buff)
- Xchar buff[RECLEN];
- X{
- X
- X long offset;
- X
- X /* Seek to the end of the file. */
- X if(fseek(dbfp,0L,SEEK_END)!=0)
- X return(DERR_WRD); /* Huh? */
- X
- X /* Get offset and calculate new id number */
- X offset=ftell(dbfp);
- X sprintf(buff,"%#04ld",(offset/(long)RECLEN));
- X
- X return(AOK);
- X}
- X
- X/**************************** setsignals *********************
- X** Set up all the signals we want to capture or ignore.
- X*************************************************************/
- Xsetsignals()
- X{
- Xstatic int diehard();
- X
- X /*
- X ** Ignore hangup and interrupt.
- X */
- X signal(SIGHUP, diehard);
- X signal(SIGINT, diehard);
- X
- X /*
- X ** Capture the rest.
- X */
- X signal(SIGQUIT, capt_sig);
- X signal(SIGILL, capt_sig);
- X signal(SIGTRAP, capt_sig);
- X signal(SIGIOT, capt_sig);
- X signal(SIGEMT, capt_sig);
- X signal(SIGFPE, capt_sig);
- X signal(SIGBUS, capt_sig);
- X signal(SIGSEGV, capt_sig);
- X signal(SIGSYS, capt_sig);
- X signal(SIGPIPE, capt_sig);
- X signal(SIGALRM, capt_sig);
- X signal(SIGTERM, capt_sig);
- X signal(SIGUSR1, capt_sig);
- X signal(SIGUSR2, capt_sig);
- X
- X return(0);
- X}
- X
- X/********************** capt_sig ****************************
- X** Capture signals.
- X** This just performs the long jump and blasts us out.
- X*************************************************************/
- Xstatic int capt_sig(sign)
- Xint sign;
- X{
- X longjmp(myjump,sign);
- X}
- X
- X/*************************** diehard ************************
- Xfor kills and other such interrupts: cleanup and exit
- X*************************************************************/
- Xstatic int diehard()
- X{
- Xcleanup();
- Xexit(1);
- X}
- X
- X/*************************** cleanup *************************
- X** Clean up after yourself.
- X** Close open files, release queues and semaphore.
- X**************************************************************/
- Xcleanup()
- X{
- X fclose(dbfp); /* Close the database file. */
- X msgctl(readq,IPC_RMID); /* Close read queue. */
- X msgctl(writeq,IPC_RMID); /* Close write queue. */
- X semctl(qsema,0,IPC_RMID); /* Release semaphore. */
- X return(0);
- X}
- X
- X/******************* makey **************************************
- X** Following routine converts an ASCII string to a key_t value.
- X** This routine originally appeared in ADVANCED PROGRAMMERS GUIDE
- X** TO UNIX SYSTEM V by R. Thomas, PHD; L. R. Rogers, and J. L. Yates.
- X** Osborne McGraw Hill.
- X******************************************************************/
- Xkey_t makey(p)
- Xchar *p;
- X{
- X key_t keyv;
- X int i;
- X
- X if(isnumber(p))
- X keyv = (key_t)atol(p);
- X else
- X {
- X keyv=(key_t)0;
- X for(i=0;i<sizeof(key_t) && p[i];i++)
- X keyv=(keyv << 8) | p[i];
- X }
- X return(keyv);
- X}
- X
- X/********************** isnumber ***************************/
- Xint isnumber(p)
- Xchar *p;
- X{
- X for( ; *p && isdigit(*p); p++) ;
- X return(*p ? 0 : 1);
- X}
- X
- X/******************************** qerror **********************
- X ** prints out the errormessage associate with a queue
- X ***************************************************************/
- Xqerror(s)
- Xchar *s; /* message prefix string */
- X{
- Xextern int errno;
- X
- Xfprintf(stderr,"QUEUE ERROR: %s:\n ",s);
- Xswitch(errno)
- X {
- X case EACCES: fprintf(stderr,
- X "message queue exists, but locked out (EACCES)\n");
- X break;
- X case ENOENT: fprintf(stderr,
- X "message queue does not exist (ENOENT)\n");
- X break;
- X case ENOSPC: fprintf(stderr,
- X "too manny message queus (ENOSPC)\n");
- X break;
- X case EEXIST: fprintf(stderr,
- X "message queue exists, but locked out (EEXIST)\n");
- X break;
- X default: fprintf(stderr,
- X "unknown error (%n)",errno);
- X break;
- X }
- Xreturn(0);
- X}
- X
- X/************ serror **********************
- X ** prints out the errormessage associate with a semaphore
- X ***************************************************************/
- Xserror(s)
- Xchar *s; /* message prefix string */
- X{
- Xextern int errno;
- X
- Xfprintf(stderr,"SEMAPHORE ERROR: %s:\n ",s);
- Xswitch(errno)
- X {
- X case EINVAL: fprintf(stderr,
- X "invalid number of semaphore sets (EINVAL)\n");
- X break;
- X case EACCES: fprintf(stderr,
- X "semaphore exists, but invalid operation (EACCES)\n");
- X break;
- X case ENOENT: fprintf(stderr,
- X "semaphore does not exist (ENOENT)\n");
- X break;
- X case ENOSPC: fprintf(stderr,
- X "too many semaphores (ENOSPC)\n");
- X break;
- X case EEXIST: fprintf(stderr,
- X "semaphore exists, but locked out (EEXIST)\n");
- X break;
- X default: fprintf(stderr,
- X "unknown error (%n)",errno);
- X break;
- X }
- X}
- X
- X
- END_OF_FILE
- if test 15460 -ne `wc -c <'dbmserv.c'`; then
- echo shar: \"'dbmserv.c'\" unpacked with wrong size!
- fi
- chmod +x 'dbmserv.c'
- # end of 'dbmserv.c'
- fi
- echo shar: End of archive 3 \(of 5\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 4 5 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 5 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- exit 0 # Just in case...
-